﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Log;

public class AppHelper
{
    #region Singleton
    static readonly Lazy<AppHelper> lazy = new Lazy<AppHelper>(() => new AppHelper());
    public static AppHelper Inst => lazy.Value;
    private AppHelper() { }
    #endregion

    #region 映射表
    public static readonly Dictionary<UInt16, string> DicLightFreqs = new Dictionary<ushort, string> {
            {1, "30次/分" },
            {2, "60次/分" },
            {3, "120次/分" },
            {4, "常亮" },
        };

    public static readonly Dictionary<UInt16, string> DicLightness = new Dictionary<ushort, string>
        {
            { 1, "0 cd/m²" },{ 2, "1000 cd/m²" },{ 3, "2000 cd/m²" },{ 4, "3000 cd/m²" },{ 5, "4000 cd/m²" },{ 6, "5000 cd/m²" },{ 7, "6000 cd/m²" },{ 8, "7000 cd/m²" }
        };
    public static readonly Dictionary<UInt16, string> DicMode = new Dictionary<ushort, string> {
            { 0, "出厂模式" },
            { 1, "待机模式" },
            { 2, "道路强化模式" },
            { 3, "主动诱导模式" },
            { 4, "防止追尾警示模式" },
            { 5, "保障模式" }
        };
    #endregion

    byte _Address;

    IniField<byte> faddress;
    FieldLevel floglevel;
    public byte Address => _Address;

    const string KEY_ADDRESS = "address";
    const string KEY_PORTNAME = "portname";
    const string KEY_BAUDRATE = "baudrate";
    const string KEY_LOG_LEVEL = "log_level";

    static readonly Dictionary<Level, string> LogLevelDic = new Dictionary<Level, string> {
            {Level.Silent,"SILENT" },
            {Level.Fatal, "FATAL" },
            {Level.Error, "ERROR" },
            {Level.Warning, "WARN" },
            {Level.User, "USER" },
            {Level.Info, "INFO" },
            {Level.Debug, "DEBUG" },
            {Level.Verbose, "VERBOSE" },
            {Level.Flooding, "FLOOD" },

    };
    static void LogHandler(Level level, string context, string message)
    {
        string header = LogLevelDic[level];

        Trace.WriteLine($"[{DateTime.Now:MM/dd HH:mm:ss}] [{header}] {context}: {message}");
    }
    public bool Init()
    {
        // init log
        Log.LogHandler = LogHandler;

        Log.Info("------------------- * START * --------------------");

        LoadConfig();

        checkFolders();

        return false;
    }
    public void Exit()
    {

    }

    public String GenerateUniqueId()
    {
        string timestampId = DateTime.Now.ToString("yyyyMMddHHmmssfff");
        return timestampId;
    }

    // check data folder
    private void checkFolders()
    {
        string dataDirectory = "data";

        if (!Directory.Exists(dataDirectory))
        {
            // 如果目录不存在，则创建它
            Directory.CreateDirectory(dataDirectory);
        }
    }

    public bool SaveAddress(byte address)
    {
        _Address = address;
        return faddress.Save(address);
    }
    public bool SaveLogLevel(string level)
    {
        return floglevel.Save(level);
    }


    public void LoadConfig()
    {
        var filePath = System.IO.Path.Combine(Environment.CurrentDirectory, Constants.CONFIG_FILENAME);

        try
        {
            ini = new INI(filePath);

            floglevel = new FieldLevel(ini, Constants.DEFAULT_LOG_LEVEL, KEY_LOG_LEVEL);

            Log.LogLevel = floglevel.Load();
        }
        catch (Exception ex)
        {
            //Log.Error(ex.Message + "(" + filePath + ")");
            Log.Error($"加载配置失败:{ex.Message}");
        }
    }
    #region Fileds
    public INI ini;
    #endregion
    #region Methods

    #endregion

    #region ini的字段操作

    public abstract class IniField<T>
    {
        readonly INI ini;
        readonly T defaultValue;
        readonly string keyword;
        public IniField(INI ini, T defaultValue, string keyword)
        {
            this.ini = ini;
            this.defaultValue = defaultValue;
            this.keyword = keyword;
        }

        public T Load()
        {
            T target = defaultValue;
            if (!ini.Configurations.ContainsKey(keyword))
            {
                return defaultValue;
            }

            string fileValue = ini.Configurations[keyword]?.Trim();
            if (!string.IsNullOrEmpty(fileValue))
            {
                T tmp = default;
                if (TryParse(fileValue, out tmp))
                {
                    target = tmp;
                }
            }
            return target;
        }

        public virtual bool TryParse(string fileValue, out T tmp)
        {
            throw new NotImplementedException();
        }
        public virtual bool Save(T v)
        {
            ini.Configurations[keyword] = v.ToString();
            return ini.Save();
        }
    }
    public class FieldInt32 : IniField<int>
    {
        public FieldInt32(INI ini, int defaultValue, string keyword) : base(ini, defaultValue, keyword)
        {
        }

        public override bool TryParse(string fileValue, out int tmp)
            => Int32.TryParse(fileValue, out tmp);
    }
    public class FieldByte : IniField<byte>
    {
        public FieldByte(INI ini, byte defaultValue, string keyword) : base(ini, defaultValue, keyword)
        {
        }

        public override bool TryParse(string fileValue, out byte tmp)
        {
            return Byte.TryParse(fileValue, out tmp);
        }
    }
    public class FieldString : IniField<string>
    {
        public FieldString(INI ini, string defaultValue, string keyword) : base(ini, defaultValue, keyword)
        {
        }

        public override bool TryParse(string fileValue, out string tmp)
        {
            tmp = fileValue;
            return true;
        }
    }

    public class FieldLevel
    {
        readonly INI ini;
        readonly Level defaultValue;
        readonly string keyword;
        public FieldLevel(INI ini, Level defaultValue, string keyword)
        {
            this.ini = ini; this.defaultValue = defaultValue; this.keyword = keyword;
        }
        public Level Load()
        {
            Level logLevel = defaultValue;
            if (ini.Configurations.ContainsKey(keyword))
            {
                string level = ini.Configurations[keyword]?.Trim().ToLower();
                foreach (var item in LogLevelDic)
                {
                    if (item.Value.ToLower() == level)
                    {
                        logLevel = item.Key;
                        break;
                    }
                }

            }
            return logLevel;
        }
        public bool Save(string level)
        {
            LogLevel = Log.Level.Error;
            string levelStr = "Error";
            foreach (var item in LogLevelDic)
            {
                if (item.Value.ToLower() == level.ToLower())
                {
                    LogLevel = item.Key;
                    levelStr = item.Value;
                    break;
                }
            }

            ini.Configurations[KEY_LOG_LEVEL] = levelStr;

            return ini.Save();
        }
    }
    #endregion

}

